package com.base.cn.platform.os.service.op.affiche;

import com.base.cn.platform.os.common.OpDataManage;
import com.base.cn.platform.os.common.constants.CacheConstants;
import com.base.cn.platform.os.common.constants.ConfigName;
import com.base.cn.platform.os.common.j2cache.CustomCacheChannel;
import com.base.cn.platform.os.common.j2cache.J2CacheRegion;
import com.base.cn.platform.os.common.mybatis.BaseBiz;
import com.base.cn.platform.os.common.mybatis.Pagination;
import com.base.cn.platform.os.common.utils.DataUtil;
import com.base.cn.platform.os.common.utils.DateUtils;
import com.base.cn.platform.os.common.utils.ObjectUtils;
import com.base.cn.platform.os.common.utils.StringUtils;
import com.base.cn.platform.os.dao.op.affiche.OpReceiveAfficheDao;
import com.base.cn.platform.os.entity.op.affiche.OpAffiche;
import com.base.cn.platform.os.entity.op.affiche.OpReceiveAffiche;
import com.base.cn.platform.os.entity.op.feedback.OpFeedback;
import com.base.cn.platform.os.entity.user.user.CusUser;
import com.base.cn.platform.os.service.course.cou.CourseService;
import com.base.cn.platform.os.service.course.cou.buy.CourseBuyRecordService;
import com.base.cn.platform.os.service.manage.config.SysConfigBiz;
import com.base.cn.platform.os.service.manage.subject.SysSubjectBiz;
import com.base.cn.platform.os.service.manage.user.SysUserBiz;
import com.base.cn.platform.os.service.op.feedback.OpFeedbackBiz;
import com.base.cn.platform.os.service.user.user.CusUserBiz;
import com.github.pagehelper.PageInfo;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 接收消息Biz
 *
 * @author zsw
 * @create 2018/6/1
 */
@Service
public class OpReceiveAfficheBiz extends BaseBiz<OpReceiveAffiche, OpReceiveAfficheDao> {
    @Autowired
    private CustomCacheChannel customCacheChannel;
    @Autowired
    private CourseService courseService;
    @Autowired
    private SysSubjectBiz sysSubjectBiz;
    @Autowired
    private SysUserBiz sysUserBiz;
    @Autowired
    private OpAfficheBiz opAfficheBiz;
    @Autowired
    private CusUserBiz cusUserBiz;
    @Autowired
    private CourseBuyRecordService courseBuyRecordService;
    @Autowired
    private SysConfigBiz sysConfigBiz;
    @Autowired
    private OpFeedbackBiz opFeedbackBiz;

    /**
     * 修改消息状态为已读
     * @param id 消息ID
     */
    public void updateReceiveAfficheById(BigDecimal id,BigDecimal userId){
        OpReceiveAffiche receiveAffiche = new OpReceiveAffiche();
        receiveAffiche.setStatus(2);
        this.updateByWhereSql(receiveAffiche," id="+id);
        if(userId.compareTo(new BigDecimal(0))!=0){
            String userAfficheCount = getUserAfficheCount(userId);
            String[] s = userAfficheCount.split("_");
            setUserAfficheCount(userId,new BigDecimal(s[1]).subtract(new BigDecimal(1)),Integer.parseInt(s[0])-1);
        }
    }

    /**
     * 修改接收消息状态
     *
     * @param userId 用户id
     */
    public void updateReceiveArticleStatusById(BigDecimal userId) {
        String whereSql = " userId =" + userId + " and status = 1 ";
        List<OpReceiveAffiche> opReceiveAfficheList = this.find(whereSql, null, null);
        String receiveAfficheIds = "";
        if (ObjectUtils.isNotEmpty(opReceiveAfficheList)) {
            receiveAfficheIds = opReceiveAfficheList.stream().map(e->e.getId().toString()).distinct().collect(Collectors.joining(","));
            receiveAfficheIds = StringUtils.subHeadTailString(receiveAfficheIds, ",");
            OpReceiveAffiche opReceiveAffiche = new OpReceiveAffiche();
            opReceiveAffiche.setStatus(2);
            this.updateByWhereSql(opReceiveAffiche," id in (" + receiveAfficheIds + ") and 'status' != 2");
            //清空缓存中的未读消息数
            String userAfficheCount = getUserAfficheCount(userId);
            String[] s = userAfficheCount.split("_");
            setUserAfficheCount(userId,new BigDecimal(0),Integer.parseInt(s[0]));
        }
    }

    /**
     * 删除消息
     *
     * @param receiveAfficheId 接收消息id
     */
    public void deleteReceiveAffiche(BigDecimal receiveAfficheId) {
        this.deleteWhereSql(" id =" + receiveAfficheId);
    }

    /**
     * 删除消息
     *
     * @param ids ID串
     */
    public void deleteReceiveAfficheIds(String ids,BigDecimal userId){
        String userIds="";
        if(userId.compareTo(new BigDecimal(0))!=0){
            userIds =userId.toString();
        }else{
            List<String> objects = new ArrayList<>();
            objects.add("userId");
            List<OpReceiveAffiche> opReceiveAffiches = this.find(" id in ("+ids+")", null, objects);
            if(ObjectUtils.isNotEmpty(opReceiveAffiches)){
                userIds = opReceiveAffiches.stream().map(e -> e.getUserId().toString()).distinct().collect(Collectors.joining(","));
            }
        }
        this.deleteWhereSql(" id in ("+ids+")");
        updateMessageCount(userIds);
    }

    /**
     * 查询接收消息列表
     *
     * @param affichePage    当前页数
     * @param receiveAffiche 接受消息实体
     * @param subjectData    是否设置专业
     * @param courseData     是否设置课程
     * @param sysUserData    是否设置创建人
     * @return
     */
    public PageInfo<OpReceiveAffiche> queryReceiveAfficheList(Pagination affichePage, OpReceiveAffiche receiveAffiche,
                                                              boolean subjectData, boolean courseData, boolean sysUserData) {
        // TODO 用户的专业的消息 全部专业的消息
        if (ObjectUtils.isNotEmpty(receiveAffiche)) {
            //将消息添加到消息列表中
            if(ObjectUtils.isNotEmpty(receiveAffiche.getUserId())){
                this.addBatchReceiveAffiche(receiveAffiche.getUserId());
            }
            String whereSql = this.getWhereSql(receiveAffiche);
            PageInfo<OpReceiveAffiche> opAfficheList = this.findPage(whereSql, affichePage, null);
            List<OpReceiveAffiche> receiveAfficheList = opAfficheList.getList();
            setSubjectAndCourseToReceiveAfficheList(receiveAfficheList, subjectData, courseData, sysUserData);
            //设置发送消息类型是反馈的引用 开始
            if(ObjectUtils.isNotEmpty(receiveAfficheList)){
               List<OpReceiveAffiche> receiveAffiches =  new ArrayList<>();
                receiveAfficheList.forEach(opReceiveAffiche -> {
                    BigDecimal userId = opReceiveAffiche.getUserId();
                    CusUser user = cusUserBiz.findById(userId);
                    opReceiveAffiche.setCusUser(user);
                    if(opReceiveAffiche.getMsgType()==3){
                        receiveAffiches.add(opReceiveAffiche);
                    }
                });
                String getAfficheIds = DataUtil.joining(receiveAffiches, (v) -> v.getAfficheId());
                if(!getAfficheIds.isEmpty()){
                    Map<BigDecimal, OpFeedback> bigDecimalOpFeedbackMap = opFeedbackBiz.opArticleMapByIds(getAfficheIds);
                    if(!bigDecimalOpFeedbackMap.isEmpty()){
                        for(OpReceiveAffiche opReceiveAffiche:receiveAfficheList){
                            if(opReceiveAffiche.getMsgType()==3){
                                opReceiveAffiche.setReference(bigDecimalOpFeedbackMap.get(opReceiveAffiche.getAfficheId()).getContext());
                            }
                        }
                    }
                }
            }
            //设置发送消息类型是反馈的引用  结束
            return opAfficheList;
        }
        return null;
    }

    /**
     * 批量获取管理发送的消息数据添加到接收表中
     *
     * @param userId 用户ID
     */
    @Transactional(rollbackFor = Exception.class)
    public void addBatchReceiveAffiche(BigDecimal userId) {
        // 查询用户信息
        CusUser cusUser = cusUserBiz.findById(userId);
        if (ObjectUtils.isEmpty(cusUser)) {
            return;
        }
        // 查询用户未获取的消息列表
        Date lastSystemTime = cusUser.getLastSystemTime();
        if (ObjectUtils.isEmpty(lastSystemTime)){
            //如果最后获取消息时间为空获取最后登录时间
            lastSystemTime = cusUser.getLastLoginTime();
            if(ObjectUtils.isEmpty(lastSystemTime)){
                //如果最后登录时间为空获取账号创建时间
                lastSystemTime= cusUser.getCreateTime();
            }
        }
        OpAffiche opAffiche = new OpAffiche();
        opAffiche.setCreateTime(lastSystemTime);
        List<OpAffiche> opAfficheList = opAfficheBiz.getAfficheList(opAffiche, false, false, false);
        if (ObjectUtils.isEmpty(opAffiche)) {
            return;
        }
        // 未获取消息列表按 指定专业/指定课程分组 true:按指定专业 false:按指定课程
        Map<Boolean, List<OpAffiche>> group = DataUtil.grouping(opAfficheList, (v) -> StringUtils.isEmpty(v.getCourseIds()));
        List<OpReceiveAffiche> opReceiveAfficheList = new LinkedList<>();
        // 按指定专业接收的消息
        if (group.containsKey(true)) {
            String subjectIds = cusUser.getSubjectIds();
            List<OpReceiveAffiche> receiveBySubject = group.get(true).stream()
                    .filter((v) -> StringUtils.isEmpty(v.getSubjectIds()) || this.contains(v.getSubjectIds(), subjectIds))
                    .map((v) -> this.createOpReceiveAffiche(v, userId))
                    .collect(Collectors.toList());
            opReceiveAfficheList.addAll(receiveBySubject);
        }
        // 按指定课程接收的消息
        if (group.containsKey(false)) {
            Map<String, Object> condition = Collections.singletonMap("userId", userId);
            List<Map<String, Object>> courseBuyRecordList = courseBuyRecordService.findCourseBuyRecordList(condition, false);
            if (ObjectUtils.isNotEmpty(courseBuyRecordList)) {
                String courseIds = DataUtil.joining(courseBuyRecordList, (v) -> v.get("courseId"));
                List<OpReceiveAffiche> receiveByCourse = group.get(false).stream()
                        .filter((v) -> this.contains(v.getCourseIds(), courseIds))
                        .map((v) -> this.createOpReceiveAffiche(v, userId))
                        .collect(Collectors.toList());
                opReceiveAfficheList.addAll(receiveByCourse);
            }
        }
        if (ObjectUtils.isNotEmpty(opReceiveAfficheList)) {
            batchSave(opReceiveAfficheList);
        }
        // 更新用户最后获取消息时间
        cusUser.setLastSystemTime(new Date());
        cusUserBiz.updateById(cusUser,null);
    }

    /**
     * 给消息设置 课程
     *
     * @param str course
     * @param receiveAfficheList
     */
    public List<OpReceiveAffiche> setCourseToAfficheList(List<OpReceiveAffiche> receiveAfficheList, String str) {
        if (ObjectUtils.isNotEmpty(receiveAfficheList)) {
            String afficheCourse = "";
            for (OpReceiveAffiche affiche : receiveAfficheList) {
                if (str.equals("course") && StringUtils.isNotEmpty(affiche.getCourseIds())) {
                    afficheCourse += StringUtils.subHeadTailString(affiche.getCourseIds(), ",") + ",";
                }
            }
            String courseIds = OpDataManage.getCourseId(afficheCourse);
            Map<BigDecimal, Map<String, Object>> courseMap = null;
            if (StringUtils.isNotEmpty(courseIds)) {
                if (str.equals("course")) {
                    courseMap = courseService.findCourseToMapByIds(courseIds, false, false, false);
                }
            }
            if (ObjectUtils.isNotEmpty(courseMap)) {
                List<BigDecimal> courseIdList = new ArrayList<>(courseMap.keySet());
                for (OpReceiveAffiche affiche : receiveAfficheList) {
                    List<Map<String, Object>> courseListMap = new ArrayList<>();
                    for (BigDecimal courseId : courseIdList) {
                        if (StringUtils.isNotEmpty(affiche.getCourseIds())) {
                            if (affiche.getCourseIds().contains("," + courseId.toString() + ",") && str.equals("course")) {
                                courseListMap.add(courseMap.get(courseId));
                            }
                        }
                    }
                    if (str.equals("course")) {
                        affiche.setCourseList(courseListMap);
                    }
                }
            }
        }
        return receiveAfficheList;
    }

    /**
     * 批量系统发布消息
     * Map<String,String> 中 userId，context，msgType
     * @param json
     */
    public void sendAfficheToUser(String json) {
        if (ObjectUtils.isNotEmpty(json)) {
            Gson gson = new Gson();
            List<OpReceiveAffiche> afficheList = gson.fromJson(json,new TypeToken<List<OpReceiveAffiche>>(){}.getType());
            afficheList.forEach((v) -> {
                v.setAfficheId(new BigDecimal("0"));
                v.setStatus(1);
                setUpdateNum(v.getUserId());
            });
            this.batchSave(afficheList);
        }
    }

    /***
     * 批量发送消息
     * @param message 消息内容
     * @param msgType 消息类型，1管理员发送，2系统自动生成
     * @param userIdList 用户ID列表
     */
    public void batchSendAffiche(String message,int msgType,List<BigDecimal> userIdList){
        List<OpReceiveAffiche> list = new ArrayList<>();
        userIdList.forEach(userId->{
            OpReceiveAffiche affiche = new OpReceiveAffiche();
            affiche.setUserId(userId);
            affiche.setMsgType(msgType);
            affiche.setContext(message);
            affiche.setStatus(1);//未读
            list.add(affiche);
        });
        this.batchSave(list);
    }

    /**
     * 获取用户新消息数
     * @param userId
     * @return
     */
    public BigDecimal queryUserMsgNum(BigDecimal userId) {
        BigDecimal num = new BigDecimal(0);
        if (ObjectUtils.isNotEmpty(userId)) {
            String _num = getUserAfficheCount(userId);
            if (StringUtils.isNotEmpty(_num)) {
                String[] arr = _num.split("_");
                if (arr.length == 2) {
                    String _keyNum = arr[0];
                    String n = arr[1];
                    Integer keyNum = (Integer)customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(), CacheConstants.OP_AFFICHE_UPDATE_NUM_KEY).getValue();
                    if (StringUtils.isEmpty(keyNum)) {
                        keyNum = 0;
                    }
                    if (Integer.parseInt(_keyNum) == keyNum) {
                        num = new BigDecimal(n);
                    } else {
                        this.addBatchReceiveAffiche(userId);
                        num =  countReceiveAffiche(userId);
                        setUserAfficheCount(userId,num,keyNum);
                    }
                } else {
                    num = getMessageCount(userId,0);
                }
            } else {
                num = getMessageCount(userId,0);
            }
        }
        return num;
    }

    /**
     * 设置消息缓存
     */
    public void setUpdateNum(BigDecimal userId) {
        String userAfficheCount = getUserAfficheCount(userId);
        BigDecimal num = new BigDecimal(1);
        Integer keyNum =0;
        if(StringUtils.isNotEmpty(userAfficheCount)) {
            String[] s = userAfficheCount.split("_");
                 keyNum = Integer.parseInt(s[0]);
                 num = new BigDecimal(Integer.parseInt(s[1]));
            if (StringUtils.isNotEmpty(num)) {
                num = num.add(new BigDecimal(1));
                }
        }
        setUserAfficheCount(userId,num,keyNum);
    }

    //获取未读消息数
    public BigDecimal countReceiveAffiche(BigDecimal userId) {
        String whereSql ="userId = "+userId+" and status = 1";
        return  this.count(whereSql);
    }


    /**
     * 发送消息
     * @param userId 接受消息的用户id
     * @param context 发送内容
     * @param msgType 发送的类型 消息类型，1管理员发送，2系统自动生成 3， 反馈
     * @param afficheId 如果是 管理员发送则为公告的id,如果是反馈类型，则为 反馈信息的id
     */
    public void sendAffiche(BigDecimal userId,String context,Integer msgType ,BigDecimal afficheId){
        OpReceiveAffiche opReceiveAffiche = new OpReceiveAffiche();
        opReceiveAffiche.setUserId(userId);
        opReceiveAffiche.setContext(context);
        opReceiveAffiche.setMsgType(msgType);
        opReceiveAffiche.setStatus(1);
        if(ObjectUtils.isNotEmpty(afficheId)){
            opReceiveAffiche.setAfficheId(afficheId);
        }
        this.save(opReceiveAffiche);
        //对用户消息进行缓存
        this.setUpdateNum(userId);
    }



    /**
     * 删除消息
     *
     * @param afficheRandoms ID串
     */
    public void deleteReceiveClassAfficheIds(String afficheRandoms){
        String[] split = afficheRandoms.split(",");
        StringBuilder whereSql = new StringBuilder(" afficheRandom in (");
        for(String afficheRandom :split){
            whereSql.append("'");
            whereSql.append(afficheRandom);
            whereSql.append("'");
            if (split.length>1&&!split[split.length-1].equals(afficheRandom)) {
                whereSql.append(",");
            }
        }
        whereSql.append(")");
        List<String> objects = new ArrayList<>();
        objects.add("userId");
        List<OpReceiveAffiche> opReceiveAffiches = this.find(whereSql.toString(), null, objects);

        if(ObjectUtils.isNotEmpty(opReceiveAffiches)){
            String collect = opReceiveAffiches.stream().map(e -> e.getUserId().toString()).distinct().collect(Collectors.joining(","));
            updateMessageCount(collect);
        }
        this.deleteWhereSql(whereSql.toString());
    }

    /**
     * 修改消息数量
     * @param opReceiveAffiches
     */
    private void updateMessageCount(String  opReceiveAffiches){
        if (ObjectUtils.isNotEmpty(opReceiveAffiches)) {
            String[] split = opReceiveAffiches.split(",");
            for(String userId :split){
                BigDecimal bigDecimal = new BigDecimal(userId);
                String userAfficheCount = getUserAfficheCount(bigDecimal);
                String[] s = userAfficheCount.split("_");
                setUserAfficheCount(bigDecimal,new BigDecimal(s[1]).subtract(new BigDecimal(1)),Integer.parseInt(s[0]));
            }
        }
    }

    //===================================================================================

    /**
     * 判断是否包含指定id(课程或专业)
     *
     * @param x 消息指定的id(课程或专业)
     * @param y 用户购买的id(课程或专业)
     * @return {@code true} 包含,否则返回{@code false}
     */
    private boolean contains(String x, String y) {
        return Stream.of(y.split(",")).anyMatch((v) -> x.contains("," + v + ","));
    }

    /**
     * 创建接收到的消息
     *
     * @param opAffiche
     * @param userId
     * @return
     */
    public OpReceiveAffiche createOpReceiveAffiche(OpAffiche opAffiche, BigDecimal userId) {
        OpReceiveAffiche opReceiveAffiche = new OpReceiveAffiche();
        opReceiveAffiche.setUserId(userId);
        opReceiveAffiche.setAfficheId(opAffiche.getId());
        opReceiveAffiche.setContext(opAffiche.getContext());
        opReceiveAffiche.setMsgType(opAffiche.getMsgType());
        opReceiveAffiche.setStatus(1);
        setUpdateNum(userId);
        return opReceiveAffiche;
    }

    /**
     * 列表设置添加扩展数据
     *
     * @param receiveAfficheList 消息list
     * @param subjectData        是否设置专业科目
     * @param courseData         是否设置课程
     * @return
     */
    private List<OpReceiveAffiche> setSubjectAndCourseToReceiveAfficheList(List<OpReceiveAffiche> receiveAfficheList, boolean subjectData, boolean courseData, boolean sysUserData) {
        if (ObjectUtils.isNotEmpty(receiveAfficheList)) {
            if (subjectData) {
                sysSubjectBiz.setSubjectData(receiveAfficheList, subjectData);
            }
            if (courseData) {
                receiveAfficheList = this.setCourseToAfficheList(receiveAfficheList, "course");
            }
            if (sysUserData) {
                sysUserBiz.setSysUserData(receiveAfficheList, sysUserData);
            }
        }
        return receiveAfficheList;
    }

    //拼接专业科目查询条件
    private String getSubjectCondition(String subjectIds) {
        subjectIds = DataUtil.filterNotNumberStr(subjectIds);
        if (StringUtils.isNotEmpty(subjectIds)) {
            return Stream.of(subjectIds.split(","))
                    .map((v) -> "( subjectIds like '%," + v + ",%')")
                    .collect(Collectors.joining(" or ", " and ((subjectIds is null or subjectIds = '') or ", ")"));
        }
        return "";
    }

    /**
     *设置用户消息缓存
     * @param userId 用户ID
     * @param num
     */
    private void setUserAfficheCount(BigDecimal userId,BigDecimal num,Integer keyNum){
        customCacheChannel.set(J2CacheRegion.ONE_DAY_REGION.getKey(), CacheConstants.USER_MSG_NUM_TAG + userId, keyNum+"_"+num);
    }
    /**
     *获取用户消息缓存的value
     * @param userId 用户ID
     */
    private String getUserAfficheCount(BigDecimal userId){
        return (String) customCacheChannel.get(J2CacheRegion.ONE_DAY_REGION.getKey(),CacheConstants.USER_MSG_NUM_TAG + userId).getValue();
    }

    /**
     * 获取消息数
     * @param userId
     * @return
     */
    private BigDecimal getMessageCount(BigDecimal userId,Integer keyNum){
        this.addBatchReceiveAffiche(userId);
        BigDecimal num =  countReceiveAffiche(userId);
        setUserAfficheCount(userId,num,keyNum);
        return num;
    }

    /**
     * sql模板
     *
     * @param receiveAffiche 查询条件
     * @return
     */
    private String getWhereSql(OpReceiveAffiche receiveAffiche) {
        StringBuilder whereSql = new StringBuilder(" 1=1 ");
        if (StringUtils.isNotEmpty(receiveAffiche.getContext())) {
            whereSql.append(" and context like concat('%','").append(receiveAffiche.getContext()).append("','%')");
        }
        if (StringUtils.isNotEmpty(receiveAffiche.getStatus())) {
            whereSql.append(" and status =").append(receiveAffiche.getStatus());
        }
        if (DataUtil.idIsNotNull(receiveAffiche.getCreateUserId())) {
            whereSql.append(" and createUserId =").append(receiveAffiche.getCreateUserId());
        }
        if (StringUtils.isNotEmpty(receiveAffiche.getCreateTime())) {
            whereSql.append(" and createTime >='").append(DateUtils.format(receiveAffiche.getCreateTime(), "yyyy-MM-dd HH:mm:ss")).append("'");
        }
        if (StringUtils.isNotEmpty(receiveAffiche.getSubjectIds())) {
            whereSql.append(getSubjectCondition(receiveAffiche.getSubjectIds()));
        }
        if (StringUtils.isNotEmpty(receiveAffiche.getMsgType())) {
            whereSql.append(" and msgType =").append(receiveAffiche.getMsgType());
        }
        if (DataUtil.idIsNotNull(receiveAffiche.getUserId())) {
            whereSql.append(" and userId =").append(receiveAffiche.getUserId());
        }
        if (DataUtil.idIsNotNull(receiveAffiche.getAfficheId())) {
            whereSql.append(" and afficheId =").append(receiveAffiche.getAfficheId());
        }
        if (DataUtil.idIsNotNull(receiveAffiche.getClassId())){
            whereSql.append(" and classId =").append(receiveAffiche.getClassId());
        }
        if (StringUtils.isNotEmpty(receiveAffiche.getAfficheRandom())){
            whereSql.append(" and afficheRandom = '").append(receiveAffiche.getAfficheRandom()).append("'");
        }
        if (DataUtil.isPositive(receiveAffiche.getOrder())) {
            whereSql.append(" order by ").append(receiveAffiche.getOrder() == 1 ? " createTime asc" : " createTime desc");
        }
        return whereSql.toString();
    }

}
